import ioc.bean.People;
import ioc.config.BeanRegisteredConfig;
import ioc.config.ScopeLazyConfig;
import ioc.config.condition.ConditionConfig;
import ioc.config.factorybean.FactoryBeanConfig;
import ioc.config.imports.ImportsConfig;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.util.Arrays;
import java.util.Map;

/**
 * 给容器中注册组件；
 * 1）、包扫描 + 组件标注注解（@Controller/@Service/@Repository/@Component）[自己写的类]
 * 2）、@Bean[导入的第三方包里面的组件]
 * 3）、@Import[快速给容器中导入一个组件]
 * 3.1）、@Import(要导入到容器中的组件)；容器中就会自动注册这个组件，id默认是全类名
 * 3.2）、ImportSelector:返回需要导入的组件的全类名数组；
 * 3.3）、ImportBeanDefinitionRegistrar:手动注册bean到容器中
 * 4）、使用 Spring 提供的 FactoryBean（工厂Bean）;
 * 4.1）、默认获取到的是工厂 bean 调用 getObject 创建的对象
 * 4.2）、要获取工厂 Bean 本身，我们需要给 id 前面加一个 &（&colorFactoryBean）
 */
public class T01_BeanRegistered {
    GenericApplicationContext context;

    @Test
    public void scope() {
        context = new AnnotationConfigApplicationContext(ScopeLazyConfig.class);
        People tmp = context.getBean(People.class);
        System.out.println("bean类型：" + tmp);

        Object bean1 = context.getBean("tmp");
        Object bean2 = context.getBean("tmp");
        System.out.println("bean1：" + bean1);
        System.out.println("bean2：" + bean2);
    }

    @Test
    public void lazy() {
        context = new AnnotationConfigApplicationContext(ScopeLazyConfig.class);
        People tmp = (People) context.getBean("tmpLazy");
    }

    @Test
    public void imports() {
        context = new AnnotationConfigApplicationContext(ImportsConfig.class);
    }

    @Test
    public void factoryBean() {
        context = new AnnotationConfigApplicationContext(FactoryBeanConfig.class);
        // 工厂 Bean 获取的是调用 getObject 创建的对象
        Object bean2 = context.getBean("colorFactoryBean");
        Object bean3 = context.getBean("colorFactoryBean");
        System.out.println("bean的类型：" + bean2.getClass());
        System.out.println(bean2 == bean3);

        Object bean4 = context.getBean("&colorFactoryBean");
        System.out.println(bean4.getClass());
    }

    @Test
    public void condition() {
        context = new AnnotationConfigApplicationContext(ConditionConfig.class);
        ConfigurableEnvironment environment = context.getEnvironment();
        // 动态获取环境变量的值；Windows 10
        String property = environment.getProperty("os.name");
        System.out.println("当前操作系统:" + property);

        String[] namesForType = context.getBeanNamesForType(People.class);
        System.out.println(Arrays.toString(namesForType));
        Map<String, People> persons = context.getBeansOfType(People.class);
        System.out.println(persons);
    }

    @Test
    public void ann() {
        context = new AnnotationConfigApplicationContext(BeanRegisteredConfig.class);
        People bean = context.getBean(People.class);
        System.out.println(bean);
        printBeans();
        context.close();

        System.out.println("=======================================================================================");

        context = new GenericApplicationContext();
        context.registerBean(BeanRegisteredConfig.class);
        context.refresh();
        printBeans();
        context.registerBean(People.class, People::new);
        bean = (People) context.getBean("ioc.bean.People");
        System.out.println(bean);
        context.registerBean("People123", People.class, People::new);
        bean = (People) context.getBean("People123");
        System.out.println(bean);
        context.close();
    }

    @Test
    public void xml() {
        ApplicationContext context = new ClassPathXmlApplicationContext("BeanRegistered.xml");
        People bean = (People) context.getBean("People");
        System.out.println(bean);

        // 打印 IOC 容器中所有 People 类型的 bean 的名称
        String[] namesForType = context.getBeanNamesForType(People.class);
        for (String name : namesForType) {
            System.out.println(name);
        }
    }

    @AfterEach
    public void printBeans() {
        System.out.println("============容器中的对象==========");
        String[] definitionNames = context.getBeanDefinitionNames();
        for (String name : definitionNames) {
            System.out.println(name);
        }
        System.out.println("=================================");
    }
}
